package easier.app.x.result.pic;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import androidx.annotation.Nullable;
import easier.app.x.BuildConfig;
import easier.app.x.CommonCode;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 压缩图片
 */
public class BitmapCompressor {

    /**
     * @param file 获取文件对应的图片的inSampleSize
     *
     * @return inSampleSize
     */
    private static int calculateInSampleSize( File file ) {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inSampleSize = 1;

        try {
            FileInputStream in = new FileInputStream( file );
            BitmapFactory.decodeStream( in, null, options );
            int srcWidth = options.outWidth;
            int srcHeight = options.outHeight;

            srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
            srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;

            int longSide = Math.max( srcWidth, srcHeight );
            int shortSide = Math.min( srcWidth, srcHeight );

            float scale = ((float) shortSide / longSide);
            if ( scale <= 1 && scale > 0.5625 ) {
                if ( longSide < 1664 ) {
                    return 1;
                } else if ( longSide < 4990 ) {
                    return 2;
                } else if ( longSide > 4990 && longSide < 10240 ) {
                    return 4;
                } else {
                    return longSide / 1280;
                }
            } else if ( scale <= 0.5625 && scale > 0.5 ) {
                return longSide / 1280 == 0 ? 1 : longSide / 1280;
            } else {
                return (int) Math.ceil( longSide / (1280.0 / scale) );
            }

        } catch ( FileNotFoundException e ) {
            if ( BuildConfig.DEBUG ) {
                e.printStackTrace();
            }
            return 1;
        }
    }

    /**
     * 计算inSampleSize,保证宽度/高度均小于指定数值
     *
     * @param file   图片文件
     * @param width  宽度
     * @param height 高度
     *
     * @return inSampleSize
     */
    private static int calculateInSampleSize( File file, int width, int height ) {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inSampleSize = 1;

        try {
            FileInputStream in = new FileInputStream( file );
            BitmapFactory.decodeStream( in, null, options );
            int srcWidth = options.outWidth;
            int srcHeight = options.outHeight;

            if ( srcWidth < width && srcHeight < height ) {
                return 1;
            }

            int i = 1;
            while ( srcWidth / i > width ) {
                i *= 2;
            }

            int j = 1;
            while ( srcHeight / j > height ) {
                j *= 2;
            }

            return Math.max( i, j );

        } catch ( FileNotFoundException e ) {
            if ( BuildConfig.DEBUG ) {
                e.printStackTrace();
            }
            return 1;
        }
    }

    /**
     * 压缩指定的图片文件到指定文件,使用指定的采样率,压缩质量
     *
     * @param file         原始文件
     * @param fileTo       目标文件
     * @param inSampleSize 采样率
     * @param quality      压缩质量(1~100)
     *
     * @return 是否压缩成功
     */
    private static boolean compress( File file, File fileTo, int inSampleSize, int quality ) {

        try {
            FileInputStream inputStream = new FileInputStream( file );
            FileOutputStream outputStream = new FileOutputStream( fileTo );

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = false;
            options.inSampleSize = inSampleSize;

            Bitmap tagBitmap = BitmapFactory.decodeStream( inputStream, null, options );

            tagBitmap.compress( Bitmap.CompressFormat.JPEG, quality, outputStream );
            tagBitmap.recycle();

            outputStream.flush();

            inputStream.close();
            outputStream.close();

            return true;
        } catch ( IOException e ) {
            if ( BuildConfig.DEBUG ) {
                e.printStackTrace();
            }
            return false;
        }
    }

    /**
     * 压缩指定文件
     *
     * @param context     context
     * @param file        原始文件
     * @param maxFileSize 压缩后文件最大大小(in byte)
     *
     * @return 压缩后文件, 如果失败返回null
     */
    @Nullable
    public static File compress( Context context, File file, long maxFileSize ) {

        long length = file.length();
        if ( length <= maxFileSize ) {
            return file;
        }

        int inSampleSize = calculateInSampleSize( file );
        int quality = 60;
        File result = null;

        do {
            /* 将旧的压缩文件删除 */
            if ( result != null ) {
                boolean delete = result.delete();
                if ( !delete ) {
                    result.deleteOnExit();
                }
            }

            result = CommonCode.createTempFile( context, "temp_", ".jpg" );
            if ( result == null ) {
                /* 无法创建临时文件 */
                return null;
            }

            boolean compress = compress( file, result, inSampleSize, quality );
            if ( !compress ) {
                /* 压缩失败 */
                return null;
            }

            /* 减小参数继续压缩 */
            if ( quality == 60 ) {
                /* 1.质量减到50,再小不好了 */
                quality = 50;
            } else {
                /* 2.增大缩放系数 */
                quality = 60;
                inSampleSize = inSampleSize * 2;
            }

        } while ( result.length() > maxFileSize );

        return result;
    }

    /**
     * 同{@link #compress(Context, File, long)}
     *
     * @param context     context
     * @param uri         地址
     * @param maxFileSize 最大大小
     *
     * @return 压缩后文件
     */
    @Nullable
    public static File compress( Context context, Uri uri, long maxFileSize ) {

        File file = CommonCode.copyFromUri( context, uri, "source", null );
        if ( file != null ) {
            return compress( context, file, maxFileSize );
        } else {
            return null;
        }
    }

    /**
     * 压缩指定文件
     *
     * @param context context
     * @param file    原始文件
     *
     * @return 压缩后文件, 如果失败返回null
     */
    @Nullable
    public static File compress( Context context, File file, int width, int height ) {

        int inSampleSize = calculateInSampleSize( file, width, height );
        int quality = 60;

        File result = CommonCode.createTempFile( context, "temp_", ".jpg" );

        if ( result == null ) {
            /* 无法创建临时文件 */
            return null;
        }

        boolean compress = compress( file, result, inSampleSize, quality );
        if ( !compress ) {
            /* 压缩失败 */
            return null;
        }

        return result;
    }

    /**
     * 同{@link #compress(Context, File, long)}
     *
     * @param context context
     * @param uri     地址
     *
     * @return 压缩后文件
     */
    @Nullable
    public static File compress( Context context, Uri uri, int width, int height ) {

        File file = CommonCode.copyFromUri( context, uri, "source", null );
        if ( file != null ) {
            return compress( context, file, width, height );
        } else {
            return null;
        }
    }
}
